/*
*    Qizx/open 3.0 beta
*
* This code is the open-source version of Qizx.
* Copyright (C) 2004-2009 Axyana Software -- All rights reserved.
*
* The contents of this file are subject to the Mozilla Public License 
*  Version 1.1 (the "License"); you may not use this file except in 
*  compliance with the License. You may obtain a copy of the License at
*  http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
*  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
*  for the specific language governing rights and limitations under the
*  License.
*
* The Initial Developer of the Original Code is Xavier Franc - Axyana Software.
*
*/
using System;
using EvaluationException = System.Qizx.Api.EvaluationException;
using System.Qizx.XQuery;
namespace System.Qizx.XQuery.Op {

    /// <summary> Comparison on sequences.</summary>
    public abstract class GeneralComparison : Comparison {
        public GeneralComparison(Expression expr1, Expression expr2)
            : base(expr1, expr2) {
        }

        public override Expression StaticCheck(ModuleContext context, int flags) {
            operands[0] = context.staticCheck(operands[0], 0);
            operands[1] = context.staticCheck(operands[1], 0);
            return transfer(new ExecAny(getTest()), operands);
        }

        public class ExecAny : Comparison.Exec {
            internal ExecAny(Comparison.Test test) {
                this.test = test;
            }

            public virtual void dump(ExprDisplay d) {
                d.header(this);
                d.property("test", test.Name);
                d.child("left", args[0]);
                d.child("right", args[1]);
            }

            public override bool evalAsBoolean(Focus focus, EvalContext context) {
                XQValue v1 = args[0].eval(focus, context);
                XQValue v2 = null; // lazy
                int flags = (test != ValueEqOp.TEST && test != ValueNeOp.TEST) ? System.Qizx.XQuery.XQItemCompareType.COMPAR_ORDER : 0;

                for (; v1.Next(); ) {
                    if (v2 == null) {
                        v2 = args[1].eval(focus, context);
                        context.at(this);
                    } else
                        v2 = v2.BornAgain();
                    for (; v2.Next(); ) {
                        try {
                            int cmp = v1.CompareTo(v2.Item, context, flags);
                            if (System.Math.Abs(cmp) == System.Qizx.Util.Basic.Comparison.ERROR) {
                                context.error(System.Qizx.XQuery.Op.Expression.ERRC_BADTYPE, this, "values are not comparable (" + v1.ValueType + " and " + v2.ValueType + ")");
                            }
                            if (test.make(cmp))
                                return true;
                        } catch (XQTypeException e) {
                            // semantics: ??
                            context.error(System.Qizx.XQuery.Op.Expression.ERRC_BADTYPE, this, e);
                        }
                    }
                }
                // amazingly   () != item  returns false
                return false;
            }
        }
    }
}